package com.blackcattle.data.migrate.mongo.helper;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.*;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author dougs@sina.cn
 * @version 1.0.0
 */
@Slf4j
public class MongoDBHelper {

    private MongoClient mongoClient;

    private MongoDatabase db;

    public MongoDBHelper(String host, String port, String authDb, String database, String username, String password) {
        List<ServerAddress> addressList = buildAddressList(host, port);
        if(!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)){
            MongoCredential credential = MongoCredential.createCredential(username,authDb,password.toCharArray());
            MongoClientSettings settings = MongoClientSettings.builder()
                    .credential(credential)
                    .applyToClusterSettings(b -> b.hosts(addressList))
                    .build();
            mongoClient = MongoClients.create(settings);
        }else{
            MongoClientSettings settings = MongoClientSettings.builder()
                    .applyToClusterSettings(b -> b.hosts(addressList))
                    .build();
            mongoClient = MongoClients.create(settings);
        }

        db = mongoClient.getDatabase(database);
    }

    public void close(){
        if(mongoClient != null){
            mongoClient.close();
        }
        db = null;
        mongoClient = null;
    }

    public void insert(String collectionName, Object obj) {
        if(StringUtils.isEmpty(collectionName) || ObjectUtils.isEmpty(obj)){
            return;
        }
        MongoCollection<Document> collection = db.getCollection(collectionName);
        if(obj instanceof Map){
            collection.insertOne(new Document((Map) obj));
        }else if(obj instanceof List){
            insertMany(collectionName,(List) obj);
        }else{
            try {
                collection.insertOne(new Document(JSONObject.parseObject(JSON.toJSONString(obj))));
            } catch (Exception e) {
                log.error("数据处理异常", e);
            }
        }
    }

    private void insertMany(String collectionName, List objs) {
        MongoCollection<Document> collection = db.getCollection(collectionName);

        List<Document> docs = new ArrayList<>(objs.size());
        objs.forEach(obj-> {
            if(obj instanceof Map){
                docs.add(new Document((Map) obj));
            }else{
                try {
                    docs.add(new Document(JSONObject.parseObject(JSONObject.toJSONString(obj))));
                } catch (Exception e) {
                    log.error("数据处理异常", e);
                }
            }
        });

        collection.insertMany(docs);
    }

    public void update(String collectionName, Bson filter , Map obj) {
        MongoCollection<Document> collection = db.getCollection(collectionName);
        collection.replaceOne(filter,new Document(obj));
    }

    public List<Map> findList(String collectionName, Bson filter, Bson sort, int limit) {
        List<Map> result = new ArrayList<>();

        MongoCollection<Document> collection = db.getCollection(collectionName);
        FindIterable<Document> doc = collection.find(filter).sort(sort).limit(limit);
        MongoCursor s = doc.iterator();
        while (s.hasNext()){
            result.add((Map)s.next());
        }

        return result;
    }

    public Map findOne(String collectionName, Bson filter ) {
        MongoCollection<Document> collection = db.getCollection(collectionName);
        FindIterable<Document> doc = collection.find(filter);
        return doc.first();
    }

    public Map findOne(String collectionName) {
        MongoCollection<Document> collection = db.getCollection(collectionName);
        FindIterable<Document> doc = collection.find();
        return doc.first();
    }

    private List<ServerAddress> buildAddressList(String hosts,String ports){
        String[] hostStr = hosts.split(",");
        String[] portStr = ports.split(",");

        List<ServerAddress> addressList = new ArrayList<>();

        for(int i=0;i<hostStr.length;i++){
            addressList.add(new ServerAddress(hostStr[i],getPort(portStr,i)));
        }

        return addressList;
    }

    private int getPort(String[] ports,int idx){
        int port = 27017;

        try {
            for (int i = 0; i < ports.length; i++) {
                if(idx == i){
                    return Integer.parseInt(ports[i]);
                }
            }
        } catch (Exception e) {
            log.error("数据处理异常", e);
        }

        return port;
    }
}
